/*!

@author
*/
#include <stdafx.h>

#include "Chronometer.h"


//! Default Constructor
Chronometer::Chronometer()
{
#if defined _WIN32 | _WIN64
	m_bUsingQPF         = false;
	m_bTimerStopped     = true;
	m_llQPFTicksPerSec  = 0;

	m_llStopTime        = 0;
	m_llLastElapsedTime = 0;
	m_llBaseTime        = 0;

	LARGE_INTEGER liTicksPerSec;
	m_bUsingQPF = (bool) (QueryPerformanceFrequency( &liTicksPerSec ) != 0);
	m_llQPFTicksPerSec = liTicksPerSec.QuadPart;
#elif __GNUC__
	m_bTimerStopped     = true;
	m_llStopTime        = 0;
	m_llLastElapsedTime = 0;
	m_llBaseTime        = 0;
#endif

}

//! Reset the Chronometer
void Chronometer::Reset()
{
#if defined _WIN32 | _WIN64
	if( !m_bUsingQPF )
		return;

	// Get either the current time or the stop time
	LARGE_INTEGER liTime;
	if( m_llStopTime != 0 )
		liTime.QuadPart = m_llStopTime;
	else
		QueryPerformanceCounter( &liTime );

	m_llBaseTime        = liTime.QuadPart;
	m_llLastElapsedTime = liTime.QuadPart;
	m_llStopTime        = 0;
	m_bTimerStopped     = FALSE;
#elif __GNUC__
	m_llBaseTime		= get_usecs();
	m_llLastElapsedTime	= m_llBaseTime;
	m_llStopTime        = 0;
	m_bTimerStopped     = false;

#endif

}

//! Start Chronometer
void Chronometer::Start()
{
#if defined _WIN32 | _WIN64
	if( !m_bUsingQPF )
		return;

	// Get either the current time or the stop time
	LARGE_INTEGER liTime;
	if( m_llStopTime != 0 )
		liTime.QuadPart = m_llStopTime;
	else
		QueryPerformanceCounter( &liTime );

	if( m_bTimerStopped )
		m_llBaseTime += liTime.QuadPart - m_llStopTime;
	m_llStopTime = 0;
	m_llLastElapsedTime = liTime.QuadPart;
	m_bTimerStopped = FALSE;
#elif __GNUC__

	int64 usecs;
	if( m_llStopTime != 0 )
		usecs = m_llStopTime;
	else
		usecs = get_usecs();
	if( m_bTimerStopped )
		m_llBaseTime += usecs - m_llStopTime;
	m_llStopTime = 0;
	m_llLastElapsedTime = usecs;
	m_bTimerStopped = false;

#endif

}

//! Stop Chronometer
void Chronometer::Stop()
{
#if defined _WIN32 | _WIN64
	if( !m_bUsingQPF )
		return;

	if( !m_bTimerStopped )
	{
		// Get either the current time or the stop time
		LARGE_INTEGER liTime;
		if( m_llStopTime != 0 )
			liTime.QuadPart = m_llStopTime;
		else
			QueryPerformanceCounter( & liTime );

		m_llStopTime = liTime.QuadPart;
		m_llLastElapsedTime = liTime.QuadPart;
		m_bTimerStopped = TRUE;
	}
#elif __GNUC__

	if( !m_bTimerStopped )
	{
		// Get either the current time or the stop time
		int64 usecs;
		if( m_llStopTime != 0 )
			usecs = m_llStopTime;
		else
			usecs = get_usecs();

		m_llStopTime = usecs;
		m_llLastElapsedTime = usecs;
		m_bTimerStopped = true;
	}

#endif

}

//! 
void Chronometer::Advance()
{
#if defined _WIN32 | _WIN64

	if( !m_bUsingQPF )
		return;

	m_llStopTime += m_llQPFTicksPerSec/10;
#elif __GNUC__

	m_llStopTime += 100000;

#endif

}

//! 
double Chronometer::GetAbsoluteTime()
{
#if defined _WIN32 | _WIN64
	if( !m_bUsingQPF )
		return -1.0;

	// Get either the current time or the stop time
	LARGE_INTEGER liTime;
	if( m_llStopTime != 0 )
		liTime.QuadPart = m_llStopTime;
	else
		QueryPerformanceCounter( & liTime );

	double fTime = liTime.QuadPart / (double) m_llQPFTicksPerSec;

	return fTime;
#elif __GNUC__

	// Get either the current time or the stop time
	int64 usecs;
	if( m_llStopTime != 0 )
		usecs = m_llStopTime;
	else
		usecs = get_usecs();

	double fTime = (double)usecs / 1000000;

	return fTime;

#endif

}

//! Get Current Time from start
double Chronometer::GetTime()
{
#if defined _WIN32 | _WIN64

	if( !m_bUsingQPF )
		return -1.0;

	// Get either the current time or the stop time
	LARGE_INTEGER liTime;
	if( m_llStopTime != 0 )
		liTime.QuadPart = m_llStopTime;
	else
		QueryPerformanceCounter( & liTime );

	double fAppTime = (double) ( liTime.QuadPart - m_llBaseTime ) / (double) m_llQPFTicksPerSec;

	return fAppTime;
#elif __GNUC__

	// Get either the current time or the stop time
	int64 usecs;
	if( m_llStopTime != 0 )
		usecs = m_llStopTime;
	else
		usecs = get_usecs();

	double fAppTime = (double) ( usecs - m_llBaseTime ) / 1000000;

	return fAppTime;

#endif

}

//! Get elapsed time from the last call of this method or from start if is the first call
double Chronometer::GetElapsedTime()
{
#if defined _WIN32 | _WIN64

	if( !m_bUsingQPF )
		return -1.0;

	// Get either the current time or the stop time
	LARGE_INTEGER liTime;
	if( m_llStopTime != 0 )
		liTime.QuadPart = m_llStopTime;
	else
		QueryPerformanceCounter( & liTime );

	double fElapsedTime = (double) ( liTime.QuadPart - m_llLastElapsedTime ) / (double) m_llQPFTicksPerSec;
	m_llLastElapsedTime = liTime.QuadPart;

	return fElapsedTime;
#elif __GNUC__

	// Get either the current time or the stop time
	int64 usecs;
	if( m_llStopTime != 0 )
		usecs = m_llStopTime;
	else
		usecs = get_usecs();

	double fElapsedTime = (double) ( usecs - m_llLastElapsedTime ) / 1000000;
	m_llLastElapsedTime = usecs;

	return fElapsedTime;

#endif

}

#ifdef __GNUC__
int64 Chronometer::get_usecs()
{
	timeval tv;
	gettimeofday(&tv, NULL);
	return (int64)tv.tv_sec * 1000000 + (int64)tv.tv_usec;
}
#endif

